? Using Sprites as Stateful Entities ● SmileBASIC Source

Sign In

*Usernames are case-sensitive
Forgot my password

Using Sprites as Stateful Entities

This guide will be updated over time until I consider it sufficiently exhaustive. If you don't see this heading, I'm probably done.

SmileBASIC's lack of a central system for objects, structs, or classes leaves many programmers used to other languages bewildered. Managing state of a bunch of different objects, such as enemies, the player's inventory, etc. can become a hassle, or a big tangle of global state, if you aren't careful. However, if you're using sprites in your game (and it's likely you are) then you have some options. In this reference guide, I will explore the concept of treating sprites themselves as "entities" that have their own state and behavior. Creation, destruction, and management will be achieved purely with vanilla SB features, and there will still be room for you to explore and improve this approach. This guide assumes you know a fair bit about the SmileBASIC language (DEFs, functions etc.) and the average use cases of sprites. This isn't a beginner's course.

Table of Contents


What's the Point?

Every good game has lots of entities. All of these entities have their own state. Entities often are spawned, removed, and respawned on the fly. In a language like SB with very limited data structures, this may be a very daunting and very difficult balancing act. A large number of global arrays, a bunch of helper functions, and complicated logic. However, many good games have sprites; and if we're using sprites, why not let them own some of that state? Yes, it is possible, to an extent. Soon you'll see the broad horizons (and dangerous cliffs) when using sprite features to encapsulate state and behavior for entities and objects in your programs.

Built-In Sprite State

If you're here, you probably know how to use sprites to some degree. This bit is a bit important though, so I want to reinforce it. On their own, sprites already do hold some of their own state; however, much of this state pertains entirely to how they're drawn on-screen. For simple games, accessing this state might be enough. For example, you can read the position of any sprite on-screen with SPOFS OUT. SPOFS ID% OUT X%,Y%{,Z%} As a general rule, if you can set a property of a sprite, you can read it. SPCOLOR, SPROT, you name it. These properties are state, so you're halfway there, right? Well, for more complex games, this probably isn't enough. For example, SPROT and SPOFS use integers, so you lose some precision if you want to use floats for your angles or positions. Plus, all this state is limiting since it's entirely concerned with the sprite's display on-screen. Again, for some code, this might be enough, but what if you need something more complex? What if each enemy needs a separate "world" position before being placed on-screen? What if a moving object's position needs to be a float for smoother movement, or an object has a stored velocity? What do you do, make a bunch of global values and call it a day?

SPVAR: A Sprite's Best Friend?

What if I told you you could store variables inside a sprite? You'd probably be really excited, I'm sure! Let me temper your excitement for a second: it's not exactly what it sounds like, but it comes close. Every sprite has eight internal slots for storing arbitrary data, numbered 0 through 7. Each slot can hold one float value. These slots persist inside this sprite until it is destroyed with SPCLR, and they all begin with a default value of 0. You can think of each sprite having its own 8-element float array. The SPVAR functions are used to read and write to this "array." 'set slot 0 in sprite 12 to 3.45 SPVAR 12,0,3.45 'get slot 0's value in sprite 12 (will be 3.45) VAR#=SPVAR(12,0)

An Adventurous Example

Imagine a game where you play a brave warrior slaying numerous beasts. Obviously, each monster needs its own HP count. In an object-oriented language, this is a piece of cake: make a Monster class, give it an HP property, and allow it to change. We lack that luxury, though. We could use a fixed global array for holding monster HP, indexed by sprite ID number. Maybe we could create a complex object factory system and store data in complicated structures. At the end of the day, though, it's all global state, and it's all arrays. If we're creating sprites for each of these monsters, we might as well use them. We can assign a specific SPVAR slot to each monster's HP level. We'll go with 0, since that's easy. Let's have the player fight some slimes, who each have 50 HP. Well first, we need a function to spawn a slime. Here, we'll assume the slime graphic is on SPDEF template 22. 'make us some slimes! DEF SPAWNSLIME 'get a free sprite ID VAR ID%=SPSET(0,511,22) 'give the slime 50 HP SPVAR ID%,0,50 END Here, we get a new sprite ID and make it into a sprite (more on the SPSET() function later.) Obvious things like sprite placement are omitted for clarity, of course. All that's important to us right now is the abstract concept of the "sprite" as some kind of entity. When the player attacks the slime, we can reduce its HP by the amount of damage done. If the slime's HP drops to (or below) 0, we can kill it and simply clear the sprite. 'read the enemy's HP value VAR ENEMYHP%=SPVAR(EID%,0) 'decrease it by the damage done DEC ENEMYHP%,DAMAGE% 'store the new HP value SPVAR EID%,0,ENEMYHP% 'if HP hits 0, kill it IF ENEMYHP%<=0 THEN 'kill animation, etc. in here. SPCLR EID% END The enemy in question (here, the slime) owns its own HP counter, by way of its sprite. When we kill the enemy, we also clear its sprite, freeing it for use later.
7 votes
  • tutorial
  • sprites
  • state
  • entities
  • objects
3 Comment(s) 12Me21 12Me21 Syntax Highlighter Received for creating the code syntax highlighter on SBS Night Person I like the quiet night and sleep late. Express Yourself SPOFS uses floats EDIT: but it seems that they're only single precision... snail_ snail_ QSP Contest 1 Contest Participant I participated in the first SmileBASIC Source QSP Contest! Helper Received for being very helpful around SmileBASIC Source Achievements Amazing Contributor Someone thinks I'm an awesome person who has done so much for the community! Achievements I refuse to trust a unit measured in "pixels" as anything other than an int in SB and I recommend others to do the same. EDIT: SB might actually use single-precision wherever it uses pixel values, which is weird and doesn't really make sense, and I'm not gonna trust it anyway. 12Me21 12Me21 Syntax Highlighter Received for creating the code syntax highlighter on SBS Night Person I like the quiet night and sleep late. Express Yourself SPSET 0,0 SPOFS 0,0.1,0.1 SPOFS OUT X,Y ?X,Y 0.1 0.1 But the value is 0.10000000149011612 rather than the closer 0.10000000000000001