ASCII - Asciimatics - how to implement effects/screens into the code

我的未来我决定 提交于 2019-12-24 00:49:15

问题


Few posts ago somebody suggested me to look into Asciimatics library for Python. i'm trying to get my head around it, using:

  • samples - https://github.com/peterbrittain/asciimatics/tree/master/samples
  • documentation - https://asciimatics.readthedocs.io/en/stable/

Yet, as I'm novice, I'm still a bit confused about few quite basic things in it. I know, that by using effect array you can create layers of code that will overwrite information on the screen, based of their position in the array. The smaller index number they has, the lower (less visible) information from them will be.

And the code I want to use it in. The goal is to put wall and footprints in top layers, and blue circle on bottom. The code is working partly, so you can still enjoy my visualization:

# Programs generate exit point along the wall, then spawn bot in random location. 
#He will move around and look for the exit, using different tools. 
#7.0 - Program randomly moves from starting point and makes 9 different steps. 
#It is forbidden for it to step in same place more than one.
#7.1 - Program not only moves, but also interact with the walls. 
#It will not move on any wall or other forbidden point that can be added to the list.
#7.2 - Added circle around the bot that travels with him

from asciimatics.screen import Screen
import os
import random
import math
import time

os.system('mode con: cols=51')


def exit_point():
    ''' Randomly select the wall, where exit point will be.
    Then select one random point along the line(wall) and create there exit point'''
    global exitX
    global exitY

    wall = random.randint(1,4)

    if wall == 1:
        exitX = random.randint(1,49)
        exitY = 0
    elif wall == 2:
        exitX = 49
        exitY = random.randint(1,49)
    elif wall == 3:
        exitX = random.randint(1,49)
        exitY = 49
    elif wall == 4:
        exitX = 0
        exitY = random.randint(1,49)


def start_point():
    ''' Select coordinates for starting point inside the wall zone,
    which is smaller by one then wall size, so it will not spawn it on the wall.'''
    global startX
    global startY

    startX = random.randint(2,48)
    startY = random.randint(2,48)


def setup(screen):
    ''' Creates wall image from #.  Red # represents Exit. 
    Then create starting point and spawn our hero @.'''
    screen.fill_polygon([[(0, 0), (50, 0), (50, 50), (0, 50)],[(1, 1), (49, 1), (49, 49), (1, 49)]])
    exit_point()
    screen.print_at("#", exitX, exitY, 1, 1)
    start_point()
    screen.print_at("@", startX, startY, 2, 1)
    screen.refresh()
    input()


def move(screen):
    ''' - First program will re-create walls, exit point and spawn our hero @.
        - Then the wall is defined as array of points. Points are added to big, 
        global list of forbidden points, where no move can be made
        - To the same list, starting point is added
        - '''

    #bring back setup screen, waste of code but more intuiative
    screen.fill_polygon([[(0, 0), (50, 0), (50, 50), (0, 50)],[(1, 1), (49, 1), (49, 49), (1, 49)]])
    screen.print_at("#", exitX, exitY, 1, 1)
    screen.print_at("@", startX, startY, 2, 1)

    #list of points where new point can not be created
    forbidden_place = []
    wall = []
    for i in range(49):
        point = [i,0]
        wall.append(point)          #wall no. 1
        point = [49,i]          
        wall.append(point)          #wall no. 2
        point = [i,49]          
        wall.append(point)          #wall no. 3
        point = [0,i]           
        wall.append(point)          #wall no. 4

    forbidden_place = wall

    #Add starting point to the forbidden points list
    point = [startX,startY]
    forbidden_place.append(point)

    #moves and looking around animation
    moves = 1
    while moves < 500:  

        #radius around our here where it will see things. Right now it's nothing else like visualisatios. 
        radius = 10
        for i in range(radius):
            XL = -(round(math.sqrt(radius*radius-i*i)))     #XL - X left, for X points on left side of the circle.
            XR =  (round(math.sqrt(radius*radius-i*i)))     #XR - X right, for X points on right side of the circle.
            Y = i                                           #iterated after Y coordinate and calculate X for left and right

            YU =  (round(math.sqrt(radius*radius-i*i)))     #YU - Y up, for Y points on the topside of the circle.
            YD = -(round(math.sqrt(radius*radius-i*i)))     #YD - Y down, for Y points on the downside of the circle.
            X = i                                           #iterated after X coordinate and calculate Y for top and bottom


            if moves > 1:           
                #if is here, otherwise it will use exit point and delete points in circle around it 
                #this part inide the if will clear last points of the radius light, 
                #by using point where hero was one move before
                screen.print_at(" ",  XR + forbidden_place[-2][0], Y  + forbidden_place[-2][1], 4, 1)
                screen.print_at(" ",  XL + forbidden_place[-2][0], Y  + forbidden_place[-2][1], 4, 1)
                #fill all holes after first two lines of the code, by making same circle, but rotated by 90deg
                screen.print_at(" ",  X + forbidden_place[-2][0],  YU + forbidden_place[-2][1], 4, 1)
                screen.print_at(" ",  X + forbidden_place[-2][0],  YD + forbidden_place[-2][1], 4, 1)

                screen.print_at(" ",  XR + forbidden_place[-2][0], -Y  + forbidden_place[-2][1], 4, 1)
                screen.print_at(" ",  XL + forbidden_place[-2][0], -Y  + forbidden_place[-2][1], 4, 1)
                #fill all holes after first two lines of the code, by making same circle, but rotated by 90deg
                screen.print_at(" ", -X + forbidden_place[-2][0],   YU + forbidden_place[-2][1], 4, 1)
                screen.print_at(" ", -X + forbidden_place[-2][0],   YD + forbidden_place[-2][1], 4, 1)  

            screen.print_at("+",  XR + forbidden_place[-1][0], Y  + forbidden_place[-1][1], 4, 1)
            screen.print_at("+",  XL + forbidden_place[-1][0], Y  + forbidden_place[-1][1], 4, 1)       
            screen.print_at("+",  X + forbidden_place[-1][0],  YU + forbidden_place[-1][1], 4, 1)
            screen.print_at("+",  X + forbidden_place[-1][0],  YD + forbidden_place[-1][1], 4, 1)

            screen.print_at("+",  XR + forbidden_place[-1][0], -Y  + forbidden_place[-1][1], 4, 1)
            screen.print_at("+",  XL + forbidden_place[-1][0], -Y  + forbidden_place[-1][1], 4, 1)      
            screen.print_at("+", -X + forbidden_place[-1][0],   YU + forbidden_place[-1][1], 4, 1)
            screen.print_at("+", -X + forbidden_place[-1][0],   YD + forbidden_place[-1][1], 4, 1)      

        #refresh wall visualisation, otherwise it would be 'eaten' by light. 
        #This part will be deleted after I learn how to use effects/scenes
        screen.fill_polygon([[(0, 0), (50, 0), (50, 50), (0, 50)],[(1, 1), (49, 1), (49, 49), (1, 49)]])
        screen.print_at("#", exitX, exitY, 1, 1)    

        #this part will generate movement points for our here. 
        #It will do it's best to not step in same place twice. So here will most likely stuck at some point. 
        #In future, there will be more logic that will allow him to move over his steps, if no other way is possible.
        moveX = forbidden_place[-1][0] + random.randint(-1,1)
        if moveX == forbidden_place[-1][0]:     
            moveY = forbidden_place[-1][1] + random.randrange(-1,2,2)   #select between -1 and 1, but not 0
        else:
            moveY = forbidden_place[-1][1] + random.randint(-1,1)       #select between -1 and 1, including 0
        point = [moveX,moveY]
        if point not in forbidden_place: 
            forbidden_place.append(point)
            screen.print_at(".", forbidden_place[-2][0], forbidden_place[-2][1], 2, 1) #footprint of the hero
            screen.print_at("@", moveX, moveY , 3, 1)                                  #hero's current position
            moves = moves + 1
        else:
            moveX = forbidden_place[-1][0]  #if point is already on the list, to prevent it overwrite variable moveX and moveY
            moveY = forbidden_place[-1][1]  #the program will clear it, by assigning it to last legit value from trace list,
        time.sleep(0.1)
        screen.refresh()
    input()

Screen.wrapper(setup)
Screen.wrapper(move)
input()

回答1:


It all depends on how you implement your new Effects... In short you need a strategy for clearing old images.

The best way to animate your aplication is to use double-buffering and just draw each new image afresh. This is the technique used inside asciimatics to prevent artifacts as you redraw the Screen. Unfortunately, it doesn't clear the Screen as you swap buffers (on refresh) and so you need to do that yourself (in v1.x). Once you have done that, you can draw overlays as needed, using separate Effects if that helps.

For example, if you made the wall the bottom Effect and made it clear the whole screen as well as drawing the walls, then your other Effects just need to draw their current image without clearing the old.



来源:https://stackoverflow.com/questions/52010828/ascii-asciimatics-how-to-implement-effects-screens-into-the-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!